package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.sound.sampled.Line;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Slf4j
@Aspect
//@Aspect：声明这是一个切面类
// （使用时需要与@Component注解一起用，表明同时将该类交给spring管理）
@Component
//  @Component： 标注Spring管理的Bean，
// 使用@Component注解在一个类上，表示将此类标记为Spring容器中的一个Bean。
public class AutoFillAspect {
    // 在方法上打上@Before注解,在有注解@AutoFill的方法运行前增强方法
    @Before("@annotation(com.sky.annotation.AutoFill)")
    public void autoFill(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
        // JoinPoint
        // 提供对连接点可用状态和有关它的静态信息的反射访问。
        // 这些信息可以从通知的主体中获得，使用特殊的形式<code>thisJoinPoint</code>。
        // 这种反射信息的主要用途是跟踪和记录应用程序。
        log.info("开始进行公共字段的填充");
        // 1.根据连接点获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 2. 根据方法签名获取到Method对象
        Method method = signature.getMethod();
        // 3.可以获取到方法身上的注解对象
        AutoFill annotation = method.getAnnotation(AutoFill.class);
        // 4.获取注解里的value值
        OperationType value = annotation.value();
        // 5.判定是INSERT 还是 UPDATE
        //  5.1 准备要赋值的数据
        Long id = BaseContext.getCurrentId();
        LocalDateTime now = LocalDateTime.now();
        if (value == OperationType.INSERT){
            // 5.2 如果是INSERT,就要给四个字段进行赋值
            // 5.3 通过连接点获取方法的参数
            Object args = joinPoint.getArgs()[0];
            // 5.4 获取参数的字节码对象
            Class aClass = args.getClass();
            // 5.5 获取类里面的属性
            Field createTime = aClass.getDeclaredField("createTime");
            Field updateTime = aClass.getDeclaredField("updateTime");
            Field createUser = aClass.getDeclaredField("createUser");
            Field updateUser = aClass.getDeclaredField("updateUser");
            // 5.6 暴力反射
            createTime.setAccessible(true);
            updateTime.setAccessible(true);
            createUser.setAccessible(true);
            updateUser.setAccessible(true);
            //7.给属性赋值
            createTime.set(args,now);
            updateTime.set(args,now);
            createUser.set(args,id);
            updateUser.set(args,id);
        }else {
            Object args = joinPoint.getArgs()[0];
            Class aClass = args.getClass();
            Field updateUser = aClass.getDeclaredField("updateUser");
            Field updateTime = aClass.getDeclaredField("updateTime");
            updateTime.setAccessible(true);
            updateUser.setAccessible(true);
            updateTime.set(args,now);
            updateUser.set(args,id);

        }


    }
}
